module.exports = (api, opts = {}) => {
  const webpack = require('webpack');
  const path = require('path');
  const root = api.getCwd();
  const pluginOptions = opts.pluginOptions || {};
  const dllConfig = pluginOptions.dll;
  const {
    entry = {
      vender: [
        'vue/dist/vue.esm.js',
        'axios',
        'vuex',
        'vue-router'
      ]
    },
    filePath = 'dll'
  } = dllConfig;

  const resolve = dir => path.resolve(root, dir);

  const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');

  api.registerCommand(
    'dll',
    {
      description: '',
      usage: 'vue-cli-service dll'
    },
    args => {
      const Config = require('webpack-chain');
      const { red, green } = require('chalk');
      const {
        log,
        done,
        logWithSpinner,
        stopSpinner
      } = require('@vue/cli-shared-utils');

      const CleanWebpackPlugin = require('clean-webpack-plugin');

      logWithSpinner(green('Building dll files to dll...'));

      const config = new Config();

      for (const key in entry) {
        entry[key].forEach(i => {
          config.entry(key).add(i);
        });
      }

      config
        .mode('production');
      config
        .output
        .path(resolve(filePath))
        .filename('[name].dll.[hash:8].js')
        .library('[name]_[hash]')
        .end();

      config
        .plugin('CleanWebpackPlugin')
        .use(CleanWebpackPlugin)
        .end()
        .plugin('Dllplugin')
        .use(require('webpack/lib/DllPlugin'), [{
          name: '[name]_[hash]',
          path: path.join(root, filePath, '[name]-manifest.json'),
          context: root
        }])
        .end();
      config.optimization
        .minimize(true)
        .end();
      const webpackconfig = config.toConfig();

      webpack(webpackconfig, (err, stats) => {
        stopSpinner(false);
        if (err) {
          log();
          log(red(err));
          log();
          return false;
        }
        process.stdout.write(stats.toString({
          colors: true,
          modules: false,
          children: false,
          chunks: false,
          chunkModules: false
        }) + '\n\n');

        if (stats.hasErrors()) {
          console.log(red('  Build failed with errors.\n'));
          process.exit(1);
        }
        done(green('Build complete'));
      });
    }
  );

  api.configureWebpack(webpackConfig => {
    webpackConfig.plugins.push(
      ...Object.keys(entry).map(i => {
        return new webpack.DllReferencePlugin({
          context: root,
          manifest: require(resolve(`${filePath}/${i}-manifest.json`))
        });
      }),

      new AddAssetHtmlPlugin(
        Object.keys(entry).map(i => {
          return {
            filepath: resolve(`${filePath}/${i}.dll.*.js`),
            outputPath: `${opts.assetsDir}/dll`,
            publicPath: `${opts.assetsDir}/dll`,
            includeSourcemap: false
          };
        })
      )
    );
  });
};
